package yawning.mew.cat;

import yawning.mew.ProcEffect.Trigger;
import yawning.mew.character.CharacterModel.AttackResult;
import yawning.mew.sim.SimulationAction;
import yawning.mew.sim.SimulationEventAction;

public class EventRip extends SimulationEventAction {
	CatModelSimState mState;

	EventRip(CatModelSimState state) {
		super(state.mSimUtil);
		mState = state;
	}

	@Override
	public double perform() {
		int cost = mState.getEnergyCost(mState.mModel.ripCost);
		if ((mState.energyTickEv.mEnergy < cost && !mState.oocEv.isUp()) || mState.mComboPoints == 0) return SimulationAction.ACTION_FAIL;

		AttackResult result = mState.mModel.getYellowResult();

		// Rip refresh behavior is inconsistent.
		if (isUp() && (mCPs < mState.mComboPoints || mAttackPower < mState.mModel.getAttackPower() || mPCrit < mState.mModel.getMeleeCritChance())) {
			// "A more powerful spell is already in effect."
			// It definately checks AP and CPs, but not Tiger's Fury.  (Crit is an educated guess.)
			return SimulationAction.ACTION_FAIL;
		}

		if (mState.mDebug) mState.DBGF("Rip (%s)", result);

		if (result == AttackResult.MISS) {
			cost = (int) Math.round(cost * 0.2);
			mState.nrRipMiss++;
		} else if (result == AttackResult.DODGE) {
			cost = (int) Math.round(cost * 0.2);
			mState.nrRipDodge++;
		} else {
			mState.nrRipHit++;
			mState.mSimUtil.triggerProc(Trigger.YELLOW);
			mShreds = 0;
			mCPs = mState.mComboPoints;
			mAttackPower = mState.mModel.getAttackPower();
			mPCrit = mState.mModel.getMeleeCritChance();
			mTigersFury = mState.tigersFuryEv.isUp();
			mBloodInTheWaterRefresh = false;

			if (!isUp())
				schedule(mState.mModel.getRipDebuffDuration(), mState.mModel.getRipTickInterval());
			else
				extendExpiry(mState.mModel.getRipDebuffDuration() + getNextTickTime() - getExpiryTime());
			mState.mComboPoints = 0;
		}

		mState.onOoCConsumer(cost);
		return 1.0;
	}

	@Override
	public void onTick() {
		double damage = mState.mModel.levelDep.getRipBaseDmg() + mState.mModel.levelDep.getRipCpDmg() * mCPs + mAttackPower * mState.mModel.levelDep.getRipCoeff() * mCPs;
		if (mBloodInTheWaterRefresh) damage -= mState.mModel.bugBloodInTheWaterRipDmg * mCPs;
		damage *= mState.mModel.multRipGlyph;

		if (mState.mModel.getDotResult(mPCrit) == AttackResult.CRIT) {
			mState.nrRipDotCrit++;
			damage *= mState.mModel.multCrit;
			mState.mSimUtil.triggerProc(Trigger.DOTCRIT);
		} else {
			mState.nrRipDotHit++;
			mState.mSimUtil.triggerProc(Trigger.DOT);
		}

		damage *= mState.getBleedDamageMult();
		damage *= (mTigersFury) ? mState.mModel.multTigersFury : 1.0;
		mState.ripDamage += Math.round(damage);

		if (mState.mDebug) mState.DBGF("Rip Tick Damage: %d", Math.round(damage));
	}

	@Override
	public void onExpire() {
		if (mState.mDebug) mState.DBGF("Rip Expiration");
	}

	public void onShred() {
		if (mShreds < 3 && mState.mModel.shredRipExtDuration > 0) {
			if (mState.mDebug) mState.DBGF("Rip onShred (%d + 1)", mShreds);

			mShreds++;
			extendExpiry(mState.mModel.shredRipExtDuration);
		}
	}

	public void onBite() {
		if (mState.bitwEv.mInRange && mState.mModel.pBloodInTheWater > 0) {
			if (mState.mModel.pBloodInTheWater == 1.0 || mState.mSimUtil.getRandom().nextBoolean(mState.mModel.pBloodInTheWater)) {
				// I'm not certain exactly how this works.
				//
				// For now assume that it re-snapshot stats immediately, and does not
				// affect the tick timer.

				if (mState.mDebug) mState.DBGF("Rip Blood in the Water");

				//mShreds = 0; // Per 4.0.1, Glyph of Shred is NOT reset.
				//mCPs = 5; // Per 4.0.1, refresh behavior preserves the number of cps.
				mAttackPower = mState.mModel.getAttackPower();
				mPCrit = mState.mModel.getMeleeCritChance();
				mTigersFury = mState.tigersFuryEv.isUp();
				mBloodInTheWaterRefresh = true;

				extendExpiry(mState.mModel.getRipDebuffDuration() + getNextTickTime() - getExpiryTime());
			}
		}
	}

	int mShreds;
	private double mAttackPower;
	private double mPCrit;
	private int mCPs;
	boolean mTigersFury;
	boolean mBloodInTheWaterRefresh;
}
